package com.hmall.search.service.impl;

import com.alibaba.fastjson.JSON;

import com.hmall.common.dto.client.ItemClient;
import com.hmall.common.dto.PageDTO;


import com.hmall.common.dto.pojo.Item;
import com.hmall.search.pojo.HotelConstants;
import com.hmall.search.pojo.ItemDoc;
import com.hmall.search.pojo.Page;
import com.hmall.search.service.ISearchService;
import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpHost;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.indices.CreateIndexResponse;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.functionscore.FunctionScoreQueryBuilder;
import org.elasticsearch.index.query.functionscore.ScoreFunctionBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilder;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.amqp.core.QueueBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class SearchServiceImpl  implements ISearchService {

    @Autowired
    private ItemClient itemClient;
    @Autowired
    private RestHighLevelClient client;
    @Override
    public void index() {


        PageDTO list1 = itemClient.list(1, 1);
        Long total = list1.getTotal();
        System.out.println(total);
        Integer size = 1000;
        long page = total/size;
        for (Integer i = 0; i < page+1; i++) {
            PageDTO<com.hmall.common.dto.pojo.Item> pageDTO = itemClient.list(i, size);
            List<com.hmall.common.dto.pojo.Item> list = pageDTO.getList();
            BulkRequest request = new BulkRequest();

            for (Item item : list) {
                String json = JSON.toJSONString(item);
                IndexRequest indexRequest = new IndexRequest("item_doc");
                indexRequest.id(item.getId().toString());
                indexRequest.source(json, XContentType.JSON);
                request.add(indexRequest);
            }

            try {
                client.bulk(request, RequestOptions.DEFAULT);
                System.out.println("第"+i+"页加载完成");
            } catch (IOException e) {
                e.printStackTrace();
            }
        }


    }

    @Override
    public void dev() {
        CreateIndexRequest request = new CreateIndexRequest("item_doc");
        request.source(HotelConstants.MAPPING_TEMPLATE,XContentType.JSON);
        try {
            client.indices().create(request,RequestOptions.DEFAULT);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public Map<String, List<String>> filters(Page page) {
//        返回过滤的数据
        Map<String,List<String>> map = new HashMap<>();
        List<String> category = new ArrayList<>();
        map.put("category",category);
        List<String> brand = new ArrayList<>();
        map.put("brand",brand);
        List<String> price = new ArrayList<>();
        map.put("price",price);
//        添加聚合查询，分别统计分类/品牌/价格
//        建构查询请求对象 指定查询的索引的名称
        SearchRequest request = new SearchRequest("item_doc");
//        构建查询源对象
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
//        构建查询条件
        QueryBuilder queryBuilder;
//        匹配查询 指定要查询的字段，字段值
//        需要根据查询条件确定聚合范围
       queryBuilder = getQueryBuilder(page);
//       指定查询条件
       sourceBuilder.query(queryBuilder);
//       指定聚合条件
        AggregationBuilder agg = AggregationBuilders.terms("cateAgg");
        ((TermsAggregationBuilder) agg).field("category");
        sourceBuilder.aggregation(agg);
        AggregationBuilder brandAgg = AggregationBuilders.terms("brandAgg");
        ((TermsAggregationBuilder) brandAgg).field("brand");
        sourceBuilder.aggregation(brandAgg);
        AggregationBuilder priceAgg = AggregationBuilders.terms("priceAgg");
        ((TermsAggregationBuilder) priceAgg).field("price.keyword");
        sourceBuilder.aggregation(priceAgg);
//        不获取原始文档
        sourceBuilder.size(0);
//        指定查询源
        request.source(sourceBuilder);
//        发送查询请求
        try {
            SearchResponse response = client.search(request, RequestOptions.DEFAULT);
            Aggregations aggregations = response.getAggregations();
            Terms cateAgg = aggregations.get("cateAgg");
            for (Terms.Bucket bucket : cateAgg.getBuckets()) {
                String keyAsString = bucket.getKeyAsString();
                category.add(keyAsString);
            }

            Terms brandAgg1 = aggregations.get("brandAgg");
            for (Terms.Bucket bucket : brandAgg1.getBuckets()) {
                String keyAsString = bucket.getKeyAsString();
                brand.add(keyAsString);
            }

            Terms priceAgg1 = aggregations.get("priceAgg");
            for (Terms.Bucket bucket : priceAgg1.getBuckets()) {
                String keyAsString = bucket.getKeyAsString();
                price.add(keyAsString);
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
        return map;

    }

    @Override
    public PageDTO<ItemDoc> list(Page page) {
        SearchRequest request = new SearchRequest("item_doc");
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        QueryBuilder queryBuilder = getQueryBuilder(page);
//        指定查询条件
        sourceBuilder.query(queryBuilder);
//        指定分页条件
        int from = (page.getPage() - 1 )*page.getSize();
        sourceBuilder.from(from);
        sourceBuilder.size(page.getSize());
//        高亮
        HighlightBuilder highlightBuilder = new HighlightBuilder();
//        指定高亮条件
        highlightBuilder.field("name");
//        指定前缀和后缀
        highlightBuilder.preTags("<em>");
        highlightBuilder.postTags("</em>");
        sourceBuilder.highlighter(highlightBuilder);

//        相关性算法排序
        sourceBuilder.sort("_score",SortOrder.DESC);
//        默认排序
        if (page.getSortBy().equals("default")){
            sourceBuilder.sort("comment_count",SortOrder.DESC);
        }
//        指定排序
        if (!page.getSortBy().equals("default") && !StringUtils.isEmpty(page.getSortBy())) {
            sourceBuilder.sort("" + page.getSortBy(), SortOrder.DESC);
        }
//        指定查询源
        request.source(sourceBuilder);

        try {
            SearchResponse response = client.search(request, RequestOptions.DEFAULT);
//            构建结果对象
            PageDTO<ItemDoc> pageDTO = new PageDTO<>();
//            分析响应结果
            SearchHits hits = response.getHits();//第一层命中数据hits
            long total = hits.getTotalHits().value;
            System.out.println("命中了"+total);
            pageDTO.setTotal(total);
            List<ItemDoc> list = new ArrayList<>();
            SearchHit[] hits1 = hits.getHits();//获取里层的数据
//            遍历
            for (SearchHit hit : hits1) {
                String sourceAsString = hit.getSourceAsString();
                ItemDoc itemDoc = JSON.parseObject(sourceAsString, ItemDoc.class);
//                判断搜索栏是否为空
                if (!StringUtils.isEmpty(page.getKey())) {
//                获取高亮的结果
                    String name = hit.getHighlightFields().get("name").fragments()[0].string();
                    itemDoc.setName(name);
                }
//                判断status是否为1（正常）  如果是存入集合
                if (itemDoc.getStatus() == 1) {
                    list.add(itemDoc);
                }
            }
            pageDTO.setList(list);
            return pageDTO;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    private QueryBuilder getQueryBuilder(Page page) {
        QueryBuilder queryBuilder = QueryBuilders.boolQuery();
        if (StringUtils.isEmpty(page.getKey())){
            ((BoolQueryBuilder) queryBuilder).must(QueryBuilders.matchAllQuery());
        }else {
            ((BoolQueryBuilder) queryBuilder).must(QueryBuilders.matchQuery("name",page.getKey()));
        }
//        添加过滤条件
        if (!StringUtils.isEmpty(page.getBrand())){
            ((BoolQueryBuilder) queryBuilder).filter(QueryBuilders.termQuery("brand",page.getBrand()));
        }
        if (!StringUtils.isEmpty(page.getCategory())){
            ((BoolQueryBuilder) queryBuilder).filter(QueryBuilders.termQuery("category",page.getCategory()));
        }
        if (page.getMinPrice() != null){
            ((BoolQueryBuilder) queryBuilder).filter(QueryBuilders.rangeQuery("price").gt(page.getMinPrice()));
        }
        if (page.getMaxPrice() != null){
            ((BoolQueryBuilder) queryBuilder).filter(QueryBuilders.rangeQuery("price").lt(page.getMaxPrice()));
        }
//        相关性算分
        return QueryBuilders.functionScoreQuery(queryBuilder,new
                FunctionScoreQueryBuilder.FilterFunctionBuilder[]{
                new FunctionScoreQueryBuilder.FilterFunctionBuilder(QueryBuilders.termQuery("isAd",true),
                        ScoreFunctionBuilders.weightFactorFunction(10))
        });
    }
}
